#pragma once
#include "Channel.h"
#include "Poller.h"
#include "TimeStamp.h"
#include "CurrentThread.h"

#include <atomic>
#include <cstdint>
#include <memory>
#include <functional>
#include <sys/types.h>
#include <mutex>
#include <boost/any.hpp>
#include <vector>

using std::atomic;
using std::unique_ptr;
using std::function;
using std::mutex;
using std::vector;

class Poller;
class TimerQueue;
class EventLoop
{
public:
    using Functor = function<void()>;
    EventLoop();
    ~EventLoop();

    void loop();
    void quit();

    TimeStamp pollReturnTime() const { return _pollReturnTime; }
    int64_t iteration() const{ return _iteration; }

    void runInLoop(Functor cb);
    void queueInLoop(Functor cb);
    size_t queueSize() const;

    void wakeup();
    void updateChannel(Channel* channel);
    void removeChannel(Channel* channel);
    bool hasChannel(Channel* channel);

    void assertInLoopThread()
    {
        if(!isInLoopThread())
        {
            abortNotInLoopThread();
        }
    }
    bool isInLoopThread() const { return _tid == CurrentThread::tid();    }
    bool eventHandling() const { return _eventHandling; }
    void setContext(const boost::any& context) { _context = context; }
    const boost::any& getContext() const { return _context; }
    boost::any* getMutableContext() { return &_context; }
    static EventLoop* getEventLoopOfCurrentThread();

private:
    void abortNotInLoopThread();
    void handleRead();
    void doPendingFunctors();

    void printActiveChannels() const;
    using ChannelList = vector<Channel*>;

    bool _looping; // loop进行标志
    atomic<bool> _quit; // loop退出标志
    bool _eventHandling;
    bool _callingPendingFunctors;
    int64_t _iteration;
    const pid_t _tid;
    TimeStamp _pollReturnTime;
    unique_ptr<Poller> _poller;
    unique_ptr<TimerQueue> _timerQueue;

    int _wakeupFd;  // eventfd 事件循环唤醒fd 
    unique_ptr<Channel> _wakeupChannel;
    boost::any _context;

    ChannelList _activeChannels;
    Channel* _curActiveChannel;
    vector<Functor> _pendingFunctors; //待执行的跨线程回调任务队列
    mutable mutex _mutex;
};

